/*
 * vector.c
 *
 *  Created on: Sep 7, 2008
 *      Author: pierre
 */
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "lang/morestdlib.h"
#include "util/vector.h"
#include "util/debug.h"

#define INDEX(index) ((index) * vector->collectionHandler->item_size)
#define SIZE(size) ((size) * vector->collectionHandler->item_size)

VectorHandlerPtr vectorHandler_init(VectorHandlerPtr handler)
{
	assert(handler!=NULL);
	handler->buffer_size=100;
	handler->item_size=0;
	handler->dispose=NULL;
	handler->compare=NULL;
	return handler;
}

VectorPtr vector_new(VectorHandlerPtr collectionHandler)
	{
	assert(collectionHandler!=NULL);
	VectorPtr vector=(VectorPtr)Malloc(sizeof(Vector));

	if(vector==NULL)
		{
		return NULL;
		}

	if(vector_init(vector,collectionHandler)==NULL)
		{
		Free(vector);
		return NULL;
		}

	return vector;
	}

VectorPtr vector_init(VectorPtr vector,VectorHandlerPtr collectionHandler)
	{

	assert(vector!=NULL);
	assert(collectionHandler!=NULL);
	assert(collectionHandler->item_size > 0);
	assert(collectionHandler->buffer_size > 0);

	vector->collectionHandler = collectionHandler;
	vector->_bufsize= collectionHandler->buffer_size;
	vector->_size=0;
	vector->_data= (BytePtr)Malloc(SIZE(vector->_bufsize));
	if(vector->_data==NULL)
		{
		return NULL;
		}
	return vector;
	}

vector_size_t vector_size(const VectorPtr vector)
	{
	assert(vector!=NULL);
	return vector->_size;
	}


VectorPtr vector_getElementAt(const VectorPtr vector,vector_size_t index,BytePtr ptr)
	{

	assert(vector!=NULL);
	assert(0<=index);
	assert(index < vector_size(vector));
	assert(ptr!=0);
	memcpy(ptr,
			&(vector->_data[ INDEX(index) ]),
			SIZE(1)
			);

	return vector;
	}

VectorPtr vector_clear(VectorPtr vector)
	{
	assert(vector!=NULL);
	if(vector->collectionHandler->dispose != NULL)
		{
		vector_size_t i;
		for( i=0;i< vector_size(vector);++i )
			{
			BytePtr item=NULL;
			vector_getElementAt(vector,i,&item);
			if(item==NULL) continue;
			vector->collectionHandler->dispose(item);
			}
		}

	vector->_size=0;
	vector->_bufsize = 1;
	vector->_data =(BytePtr)Realloc(vector->_data,SIZE(1));
	return vector;
	}

static VectorPtr ensureCapacityHelper(VectorPtr vector,vector_size_t minCapacity)
	{
	assert(vector!=NULL);
	assert(minCapacity>=0);
	vector_size_t oldCapacity = vector->_bufsize;

	if (minCapacity > oldCapacity)
		{
		BytePtr newptr;
		vector_size_t newCapacity = oldCapacity + vector->collectionHandler->buffer_size;
		while (newCapacity < minCapacity)
			{
			newCapacity += vector->collectionHandler->buffer_size;
		    }

	    newptr= (BytePtr)Realloc(vector->_data,SIZE(newCapacity));

	    if(newptr==NULL) return NULL;
	    vector->_data=newptr;
	    vector->_bufsize = newCapacity;
		}

	return vector;
	}

VectorPtr vector_insertElementAt( VectorPtr vector,BytePtr item, vector_size_t index)
	{
	assert(vector!=NULL);
	assert(index<=vector_size(vector));
	assert(index>=0);

	if(ensureCapacityHelper(vector,vector_size(vector)+2)==NULL)
		{
		return NULL;
		}

	memmove( &(vector->_data[INDEX(index+1)]),
			 &(vector->_data[INDEX(index)]),
			 SIZE(vector_size(vector)-index)
			);

	memcpy(&(vector->_data[INDEX(index)]),&item, SIZE(1));
	vector->_size++;


	return vector;
	}

VectorPtr vector_addElement( VectorPtr vector,BytePtr item)
	{
	assert(vector!=NULL);
	return vector_insertElementAt(vector,item,vector_size(vector));
	}

void vector_dispose(VectorPtr vector)
	{
	assert(vector!=NULL);
	vector_clear(vector);
	Free(vector->_data);
	}

void vector_delete(VectorPtr vector)
	{
	assert(vector!=NULL);
	vector_dispose(vector);
	Free(vector);
	}


 vector_size_t vector_indexOfFromTo( VectorPtr vector,BytePtr item,vector_size_t start, vector_size_t end)
	 {
	 Ptr p;
	 assert(vector!=NULL);
	 assert(vector->collectionHandler->compare!=NULL);
	 assert(start< vector_size(vector));
	 assert(end<= vector_size(vector));
	 assert(start<=end);
	 while(start< end)
		{
		vector_getElementAt(vector,start,&p);


		if(vector->collectionHandler->compare(item,p)==0)
			 {
			 return start;
			 }

		++start;
		}
	 return -1;
	 }

 vector_size_t vector_indexOfFrom( VectorPtr vector,BytePtr item,vector_size_t start)
	 {
	 return vector_indexOfFromTo(vector,item,start,vector_size(vector));
	 }

 vector_size_t vector_indexOf( VectorPtr vector,BytePtr item)
	 {
	 return vector_indexOfFrom(vector,item,0);
	 }

 op_bool vector_contains( VectorPtr vector,BytePtr item)
	 {
	 return (op_bool)(vector_indexOf(vector,item)!=-1);
	 }

